package com.hospital.common.core.utils;

import lombok.extern.slf4j.Slf4j;
import org.dom4j.Document;
import org.dom4j.Element;
import org.w3c.dom.NodeList;
import org.xml.sax.InputSource;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.JAXBException;
import javax.xml.bind.Marshaller;
import javax.xml.bind.Unmarshaller;
import javax.xml.parsers.DocumentBuilder;
import javax.xml.parsers.DocumentBuilderFactory;
import javax.xml.xpath.XPath;
import javax.xml.xpath.XPathConstants;
import javax.xml.xpath.XPathExpression;
import javax.xml.xpath.XPathFactory;
import java.io.*;

/**
 * @author lvyao
 * @description xml工具类
 * @date 2021/12/22
 */
@Slf4j
public class XMLUtil {

    public static final String ENCODING = "UTF-8";

    /**
     * @param xmlDoc
     * @return
     */
    public static String xmlToString(Object xmlDoc) {
        return null;
    }

    /**
     * 将对象直接转换成String类型的 XML输出
     *
     * @param obj
     * @return
     */
    public static String convertToXml(Object obj) {
        // 创建输出流
        StringWriter sw = new StringWriter();
        try {
            // 利用jdk中自带的转换类实现
            JAXBContext context = JAXBContext.newInstance(obj.getClass());

            Marshaller marshaller = context.createMarshaller();
            // 格式化xml输出的格式
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT,
                    Boolean.TRUE);
            // 将对象转换成输出流形式的xml
            marshaller.marshal(obj, sw);
        } catch (JAXBException e) {
            log.info("将对象直接转换成String类型的 XML出现错误", e);
        }
        return sw.toString();
    }

    /**
     * 将对象根据路径转换成xml文件
     *
     * @param obj
     * @param path
     * @return
     */
    public static void convertToXml(Object obj, String path) {
        try {
            // 利用jdk中自带的转换类实现
            JAXBContext context = JAXBContext.newInstance(obj.getClass());

            Marshaller marshaller = context.createMarshaller();
            // 格式化xml输出的格式
            marshaller.setProperty(Marshaller.JAXB_FORMATTED_OUTPUT,
                    Boolean.TRUE);
            // 将对象转换成输出流形式的xml
            // 创建输出流
            FileWriter fw = null;
            try {
                fw = new FileWriter(path);
            } catch (IOException e) {
                e.printStackTrace();
            }
            marshaller.marshal(obj, fw);
        } catch (JAXBException e) {
            log.info("将对象根据路径转换成xml文件 出现错误", e);
        }
    }

    @SuppressWarnings("unchecked")
    /**
     * 将String类型的xml转换成对象
     */
    public static Object convertXmlStrToObject(Class clazz, String xmlStr) {
        Object xmlObject = null;
        try {
            JAXBContext context = JAXBContext.newInstance(clazz);
            // 进行将Xml转成对象的核心接口
            Unmarshaller unmarshaller = context.createUnmarshaller();
            StringReader sr = new StringReader(xmlStr);
            xmlObject = unmarshaller.unmarshal(sr);
        } catch (JAXBException e) {
            log.info("将String类型的xml转换成对象 出现错误", e);
        }
        return xmlObject;
    }

    @SuppressWarnings("unchecked")
    /**
     * 将file类型的xml转换成对象
     */
    public static Object convertXmlFileToObject(Class clazz, String xmlPath) {
        Object xmlObject = null;
        try {
            JAXBContext context = JAXBContext.newInstance(clazz);
            Unmarshaller unmarshaller = context.createUnmarshaller();
            FileReader fr = null;
            try {
                fr = new FileReader(xmlPath);
            } catch (FileNotFoundException e) {
                e.printStackTrace();
            }
            xmlObject = unmarshaller.unmarshal(fr);
        } catch (JAXBException e) {
            log.info("将file类型的xml转换成对象 出现错误", e);
        }
        return xmlObject;
    }

    /**
     * 将字符串转化为Document
     *
     * @param xmlDoc
     * @return
     */
    public static org.w3c.dom.Document genXmlPEdor(String xmlDoc) {
        try {
            DocumentBuilderFactory factory = DocumentBuilderFactory.newInstance();
            DocumentBuilder documentBuilder = factory.newDocumentBuilder();
            InputSource in = new InputSource(new StringReader(xmlDoc));
            return documentBuilder.parse(in);
        } catch (Exception e) {
            log.info("将字符串转化为Document出现错误", e);
            return null;
        }

    }


    /**
     * get value of element
     *
     * @param doc      org.w3c.dom.Document instance
     * @param location xpath (say: "//TXLife/TXLifeResponse/Policys")
     * @return
     */
    public static Element getElement(Document doc, String location) {
        try {
            XPathFactory pathFactory = XPathFactory.newInstance();
            XPath xpath = pathFactory.newXPath();
            XPathExpression pathExpression = xpath.compile(location);
            Object result = pathExpression.evaluate(doc, XPathConstants.NODESET);
            NodeList nodes = (NodeList) result;
            if (nodes != null && nodes.getLength() > 0) {
                Element element = (Element) nodes.item(0);
                return element;
            }
            return null;
        } catch (Exception e) {
            log.info("得到element出现错误", e);
            return null;
        }
    }

    /**
     * XML转为JDOM对象
     *
     * @param XML
     * @return
     */
    public static Document XMLToDom4j(String XML) {
        try {
            String[] str = XML.split("[?]>");
            if (str == null || str.length < 1) {
                return null;
            }
            String encoding = "GBK";

            String[] encodingList = str[0].split("\"");

            for (int i = 0; i < encodingList.length; i++) {
                if ("GBK".equals(encodingList[i].trim()) || "UTF-8".equals(encodingList[i].trim())) {
                    encoding = encodingList[i];
                    break;
                }
            }
            InputStream in_withcode = new ByteArrayInputStream(XML.getBytes(encoding));
            // 文档对象
            Document myDoc = null;
            // 解析器
            org.jdom.input.SAXBuilder sb = new org.jdom.input.SAXBuilder();
            // 文档赋值
            myDoc = (Document) sb.build(in_withcode);
            return myDoc;
        } catch (Exception e) {
            log.info("XML转为JDOM对象出现错误", e);
            return null;
        }
    }

    /**
     * XML转为JDOM对象
     *
     * @param XML
     * @return
     */
    public static org.jdom.Document XMLToJDom(String XML) {
        try {
            String[] str = XML.split("[?]>");
            if (str == null || str.length < 1) {
                return null;
            }
            String encoding = "GBK";

            String[] encodingList = str[0].split("\"");

            for (int i = 0; i < encodingList.length; i++) {
                if ("GBK".equals(encodingList[i].trim()) || "UTF-8".equals(encodingList[i].trim())) {
                    encoding = encodingList[i];
                    break;
                }
            }
            InputStream in_withcode = new ByteArrayInputStream(XML.getBytes(encoding));
            // 文档对象
            org.jdom.Document myDoc = null;
            // 解析器
            org.jdom.input.SAXBuilder sb = new org.jdom.input.SAXBuilder();
            // 文档赋值
            myDoc = sb.build(in_withcode);
            return myDoc;
        } catch (Exception e) {
            log.info("XML转为JDOM对象出现错误", e);
            return null;
        }
    }

    /**
     * 将字符串写入指定文件(当指定的父路径中文件夹不存在时，会最大限度去创建，以保证保存成功！)
     *
     * @param res      原字符串
     * @param filePath 文件路径
     * @return 成功标记
     */
    public static boolean string2File(String res, String filePath) {
        boolean flag = true;
        BufferedReader bufferedReader = null;
        BufferedWriter bufferedWriter = null;
        try {
            File distFile = new File(filePath);
            if (!distFile.getParentFile().exists()) {
                distFile.getParentFile().mkdirs();
            }
            bufferedReader = new BufferedReader(new StringReader(res));
            bufferedWriter = new BufferedWriter(new OutputStreamWriter(new FileOutputStream(distFile), "utf-8"));
            char buf[] = new char[1024];         //字符缓冲区
            int len;
            while ((len = bufferedReader.read(buf)) != -1) {
                bufferedWriter.write(buf, 0, len);
            }
            bufferedWriter.flush();
            bufferedReader.close();
            bufferedWriter.close();
        } catch (IOException e) {
            e.printStackTrace();
            flag = false;
            return flag;
        } finally {
            if (bufferedReader != null) {
                try {
                    bufferedReader.close();
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }
        return flag;
    }
}
